package 多线程.AQS;

import java.util.concurrent.Semaphore;

/**
 * Semaphore是一个计数信号量，它允许多个线程同时访问共享资源，并通过计数器来控制访问数量。
 * 它通常用来实现一个线程需要等待获取一个许可证才能访问共享资源，或者需要释放一个许可证才能完成的操作。
 *
 * Semaphore维护了一个内部计数器（许可permits），主要有两个操作，分别对应Semaphore的acquire和release方法。
 * acquire方法用于获取资源，当计数器大于0时，将计数器减1；当计数器等于0时，将线程阻塞。release方法用于释放资源，
 * 将计数器加1，并唤醒一个等待中的线程。
 *
 * 举个例子：假设停车场有5个车位，如果同时来了6辆车，那么保安只允许5辆车进入（获取许可），
 * 剩下的一辆车只能等待它们其中一辆开走（释放许可），才能进入。
 *
 * Semaphore(int permits)：构造方法，permits表示Semaphore中的许可数量，它决定了同时可以访问某个资源的线程数量。
 * Semaphore(int permits,boolean fair)：构造方法，当fair为ture，设置为公平信号量。
 * void acquire()：获取一个许可，如果没有许可，则当前线程被阻塞，直到有许可。如果有许可该方法会将许可数量减1。
 * void acquire(int permits)：获取指定数量的许可，获取成功同样将许可减去指定数量，失败阻塞。
 * void release()：释放一个许可，将许可数加1。如果有其他线程正在等待许可，则唤醒其中一个线程。
 * void release(int n)：释放n个许可。
 * int availablePermits()：当前可用许可数。
 */
public class SemaphoreTest {
    private Semaphore parking;
    //初始化许可数量
    public SemaphoreTest(int n){
        parking = new Semaphore(n);
    }
    //停车
    public void park(){
        try {
            //获取一个停车位，如果没有则阻塞
            parking.acquire();
            System.out.println(Thread.currentThread().getName()+" 停车成功！");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    //释放车位
    public void leave(){
        //释放一个车位
        parking.release();
        System.out.println(Thread.currentThread().getName()+" 离开了停车场！");
    }
    public static void main(String[] args) {
        //初始化3个停车位
        SemaphoreTest parking=new SemaphoreTest(3);
        //假设此时有5辆车需要停放
        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                //停车
                parking.park();
                try {
                    //假设每辆车停留300毫秒
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                //离开停车厂
                parking.leave();
            },"Car-"+i).start();
        }
    }
}